/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is dual-licensed under either the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree or the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree. You may select, at your option, one of the
 * above-listed licenses.
 */

package com.facebook.buck.android.build_config;

import com.google.common.collect.ImmutableList;

/** Utilities for generating a {@code BuildConfig.java} file for Android. */
public class BuildConfigs {

  /**
   * Name of the boolean global variable provided by the standard Android tools to indicate whether
   * an app was built in debug mode or not.
   */
  public static final String DEBUG_CONSTANT = "DEBUG";

  /**
   * Name of a Buck-specific global variable that indicates whether an app was built using
   * exopackage.
   */
  public static final String IS_EXO_CONSTANT = "IS_EXOPACKAGE";

  /** Name of a global variable that includes the exopackage configuration as a bitmask. */
  public static final String EXOPACKAGE_FLAGS = "EXOPACKAGE_FLAGS";

  /**
   * @see #getDefaultBuildConfigFields()
   */
  private static final BuildConfigFields DEFAULT_BUILD_CONFIG_CONSTANTS =
      BuildConfigFields.fromFields(
          ImmutableList.of(
              // DEBUG is expected by the standard Android tools.
              BuildConfigFields.Field.of("boolean", DEBUG_CONSTANT, "true"),
              // IS_EXOPACKAGE is a value we use internally for checking whether exopackage is being
              // used.
              BuildConfigFields.Field.of("boolean", IS_EXO_CONSTANT, "false"),
              BuildConfigFields.Field.of("int", EXOPACKAGE_FLAGS, "0")));

  /** Utility class: do not instantiate. */
  private BuildConfigs() {}

  /**
   * Returns a list of fields (with values) that every {@code BuildConfig.java} should declare. The
   * default value of each constant may be overridden by the {@code userFields} passed to {@link
   * #generateBuildConfigDotJava(String, String, boolean, BuildConfigFields)} when generating a
   * {@code BuildConfig.java}.
   */
  public static BuildConfigFields getDefaultBuildConfigFields() {
    return DEFAULT_BUILD_CONFIG_CONSTANTS;
  }

  /**
   * Generates the source code for an Android {@code BuildConfig.java} file with fields specified by
   * {@code userFields}.
   *
   * <p>The output will also contain a constant for every entry in the collection returned by {@link
   * #getDefaultBuildConfigFields()}.
   *
   * <p>If the name of a field in {@code userFields} matches one in the collection returned by
   * {@link #getDefaultBuildConfigFields()}, the value in the {@code userFields} map will be used.
   *
   * @param javaPackage The package for the Java class generated by this method.
   * @param useConstantExpressions If {@code true}, the value for each static final field in the
   *     generated class will be declared as the literal value in {@code userFields}. The values of
   *     such fields can be inlined by {@code javac}.
   *     <p>If {@code false}, the value for each static final field in the generated class will be
   *     declared as a non-constant expression that is guaranteed to evaluate to the same value in
   *     {@code userFields}. This ensures that the generated {@code BuildConfig.java} can still be
   *     used in Robolectric tests, but does not run the risk of its values being inlined by {@code
   *     javac}. This is important if the generated {@code BuildConfig} class is going to be swapped
   *     out by a different implementation by an Android APK.
   * @param userFields represents the fields that should be declared in the generated {@code
   *     BuildConfig} class.
   */
  public static String generateBuildConfigDotJava(
      String source,
      String javaPackage,
      boolean useConstantExpressions,
      BuildConfigFields userFields) {

    BuildConfigFields totalFields = getDefaultBuildConfigFields().putAll(userFields);
    return totalFields.generateBuildConfigDotJava(source, javaPackage, useConstantExpressions);
  }
}
